using Admin.NET.Core.Service;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Furion.DatabaseAccessor;
using Furion.DynamicApiController;
using Furion.FriendlyException;
using Mapster;
using SqlSugar;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using Admin.NET.Application.Entity;
using System.Text.Json;
using System.Text;
using System.Net.Http;
using System.Net.Http.Headers;
using Microsoft.Extensions.Configuration;
using Furion.UnifyResult;

namespace Admin.NET.Application.Service.KnowledgeBase;

/// <summary>
/// 知识库管理服务（集成Qdrant向量数据库）
/// </summary>
[ApiDescriptionSettings(Name = "knowledgeBase", Order = 380)]
[Route("api/knowledgeBase")]
public class KnowledgeBaseService : IDynamicApiController, ITransient
{
    private readonly SqlSugarRepository<Admin.NET.Application.Entity.KnowledgeBase> _knowledgeRepo;
    private readonly SqlSugarRepository<Admin.NET.Application.Entity.KnowledgeVector> _vectorRepo;
    private readonly SqlSugarRepository<Admin.NET.Application.Entity.KnowledgeCategory> _categoryRepo;
    private readonly HttpClient _httpClient;
    private readonly IConfiguration _configuration;

    public KnowledgeBaseService(
        SqlSugarRepository<Admin.NET.Application.Entity.KnowledgeBase> knowledgeRepo,
        SqlSugarRepository<Admin.NET.Application.Entity.KnowledgeVector> vectorRepo,
        SqlSugarRepository<Admin.NET.Application.Entity.KnowledgeCategory> categoryRepo,
        HttpClient httpClient,
        IConfiguration configuration)
    {
        _knowledgeRepo = knowledgeRepo;
        _vectorRepo = vectorRepo;
        _categoryRepo = categoryRepo;
        _httpClient = httpClient;
        _configuration = configuration;
    }

    /// <summary>
    /// 获取Qdrant集合信息
    /// </summary>
    [DisplayName("获取Qdrant集合信息")]
    [ApiDescriptionSettings(Name = "QdrantCollectionInfo"), HttpGet("qdrant/collection-info")]
    [NonUnify]
    public async Task<IActionResult> GetQdrantCollectionInfo()
    {
        var qdrantUrl = _configuration["RAGSettings:QdrantUrl"] ?? "http://localhost:6333";
        var collectionName = _configuration["RAGSettings:QdrantCollection"] ?? "wms_knowledge";
        var response = await _httpClient.GetAsync($"{qdrantUrl}/collections/{collectionName}");
        response.EnsureSuccessStatusCode();
        var json = await response.Content.ReadAsStringAsync();
        return new ContentResult { Content = json, ContentType = "application/json", StatusCode = 200 };
    }

    /// <summary>
    /// 获取Qdrant集合点位数量
    /// </summary>
    [DisplayName("获取Qdrant向量数量")]
    [ApiDescriptionSettings(Name = "QdrantPointsCount"), HttpGet("qdrant/points-count")]
    [NonUnify]
    public async Task<IActionResult> GetQdrantPointsCount(bool exact = true)
    {
        var qdrantUrl = _configuration["RAGSettings:QdrantUrl"] ?? "http://localhost:6333";
        var collectionName = _configuration["RAGSettings:QdrantCollection"] ?? "wms_knowledge";
        var body = new { exact };
        var content = new StringContent(JsonSerializer.Serialize(body), Encoding.UTF8, "application/json");
        var response = await _httpClient.PostAsync($"{qdrantUrl}/collections/{collectionName}/points/count", content);
        response.EnsureSuccessStatusCode();
        var json = await response.Content.ReadAsStringAsync();
        return new ContentResult { Content = json, ContentType = "application/json", StatusCode = 200 };
    }

    /// <summary>
    /// 滚动查看Qdrant集合中的点（示例）
    /// </summary>
    [DisplayName("滚动查看Qdrant点位示例")]
    [ApiDescriptionSettings(Name = "QdrantScrollPoints"), HttpGet("qdrant/scroll-points")]
    [NonUnify]
    public async Task<IActionResult> ScrollQdrantPoints(int limit = 5)
    {
        if (limit <= 0) limit = 5;
        var qdrantUrl = _configuration["RAGSettings:QdrantUrl"] ?? "http://localhost:6333";
        var collectionName = _configuration["RAGSettings:QdrantCollection"] ?? "wms_knowledge";
        var body = new { limit, with_payload = true };
        var content = new StringContent(JsonSerializer.Serialize(body), Encoding.UTF8, "application/json");
        var response = await _httpClient.PostAsync($"{qdrantUrl}/collections/{collectionName}/points/scroll", content);
        response.EnsureSuccessStatusCode();
        var json = await response.Content.ReadAsStringAsync();
        return new ContentResult { Content = json, ContentType = "application/json", StatusCode = 200 };
    }

    /// <summary>
    /// 分页查询知识库
    /// </summary>
    [DisplayName("分页查询知识库")]
    [ApiDescriptionSettings(Name = "Page"), HttpPost]
    public async Task<SqlSugarPagedList<Admin.NET.Application.Entity.KnowledgeBase>> GetPage(PageInput input)
    {
        return await _knowledgeRepo.AsQueryable()
            .WhereIF(!string.IsNullOrEmpty(input.Keyword), k => 
                k.Title.Contains(input.Keyword) || 
                k.Content.Contains(input.Keyword) || 
                k.Keywords.Contains(input.Keyword))
            .WhereIF(!string.IsNullOrEmpty(input.Category), k => k.Category == input.Category)
            .OrderByDescending(k => k.CreateTime)
            .ToPagedListAsync(input.Page, input.PageSize);
    }

    /// <summary>
    /// 添加知识
    /// </summary>
    [ApiDescriptionSettings(Name = "Add"), HttpPost]
    [DisplayName("添加知识")]
    public async Task<long> Add([FromBody] Admin.NET.Application.Entity.KnowledgeBase input)
    {
        input.LastUpdated = DateTime.Now;
        var id = await _knowledgeRepo.InsertReturnSnowflakeIdAsync(input);
        
        // 生成向量并存储到Qdrant
        await GenerateAndStoreVectorAsync(id, input.Content, input.Title);
        
        return id;
    }

    /// <summary>
    /// 更新知识
    /// </summary>
    [ApiDescriptionSettings(Name = "Update"), HttpPost]
    [DisplayName("更新知识")]
    public async Task Update([FromBody] Admin.NET.Application.Entity.KnowledgeBase input)
    {
        input.LastUpdated = DateTime.Now;
        await _knowledgeRepo.UpdateAsync(input);
        
        // 更新Qdrant中的向量
        await UpdateVectorInQdrantAsync(input.Id, input.Content, input.Title);
    }

    /// <summary>
    /// 删除知识
    /// </summary>
    [ApiDescriptionSettings(Name = "Delete"), HttpPost]
    [DisplayName("删除知识")]
    public async Task Delete([FromBody] BaseIdInput? input, [FromForm] long? fid, [FromQuery] long? qid)
    {
        var realId = (input?.Id) ?? fid ?? qid ?? 0;
        if (realId <= 0) throw new ArgumentException("无效的Id");

        // 物理删除知识
        await _knowledgeRepo.AsDeleteable().Where(k => k.Id == realId).ExecuteCommandAsync();
        
        // 从Qdrant中删除向量
        await DeleteVectorFromQdrantAsync(realId);
    }

    /// <summary>
    /// 搜索知识（使用Qdrant向量搜索）
    /// </summary>
    [DisplayName("搜索知识")]
    [ApiDescriptionSettings(Name = "Search"), HttpGet]
    public async Task<List<Admin.NET.Application.Entity.KnowledgeBase>> Search(string query, int limit = 10)
    {
        // 1. 文本搜索
        var textResults = await _knowledgeRepo.GetListAsync(k => 
            k.Title.Contains(query) || 
            k.Content.Contains(query) || 
            k.Keywords.Contains(query));

        // 2. 向量搜索（使用Qdrant）
        var vectorResults = await SearchByVectorInQdrantAsync(query, limit);

        // 3. 合并结果
        var allResults = textResults.Concat(vectorResults)
            .GroupBy(k => k.Id)
            .Select(g => g.First())
            .OrderByDescending(k => CalculateRelevanceScore(k, query))
            .Take(limit)
            .ToList();

        return allResults;
    }

    /// <summary>
    /// 使用Qdrant进行向量搜索
    /// </summary>
    private async Task<List<Admin.NET.Application.Entity.KnowledgeBase>> SearchByVectorInQdrantAsync(string query, int limit)
    {
        try
        {
            // 1. 生成查询向量
            var queryVector = await GenerateEmbeddingAsync(query);
            
            // 2. 调用Qdrant API进行向量搜索
            var qdrantResults = await SearchVectorsInQdrantAsync(queryVector, limit);
            
            // 3. 根据Qdrant返回的ID获取知识库记录
            var results = new List<Admin.NET.Application.Entity.KnowledgeBase>();
            foreach (var result in qdrantResults)
            {
                var knowledge = await _knowledgeRepo.GetByIdAsync(result.KnowledgeId);
                if (knowledge != null)
                {
                    knowledge.SimilarityScore = result.Score;
                    results.Add(knowledge);
                }
            }
            
            return results.OrderByDescending(k => k.SimilarityScore).ToList();
        }
        catch (Exception ex)
        {
            // 记录错误但不影响主流程
            Console.WriteLine($"Qdrant向量搜索失败: {ex.Message}");
            return new List<Admin.NET.Application.Entity.KnowledgeBase>();
        }
    }

    /// <summary>
    /// 生成文本嵌入向量（使用OpenAI Embeddings API）
    /// </summary>
    private async Task<float[]> GenerateEmbeddingAsync(string text)
    {
        // 确保text不为null，避免序列化时出现"Value cannot be null"错误
        text = text ?? string.Empty;
        
        if (string.IsNullOrWhiteSpace(text))
        {
            return GenerateSimpleVector("");
        }
        
        var apiKey = _configuration["RAGSettings:EmbeddingApiKey"];
        var apiUrl = _configuration["RAGSettings:EmbeddingApiUrl"];
        
        if (string.IsNullOrEmpty(apiKey) || string.IsNullOrEmpty(apiUrl))
        {
            // 如果没有配置API，使用简化的向量生成
            Console.WriteLine("警告: Embedding API 未配置，使用简化向量生成");
            return GenerateSimpleVector(text);
        }

        // 确保model不为null，避免序列化问题
        var model = _configuration["RAGSettings:EmbeddingModel"] ?? "ragflow";
        if (string.IsNullOrWhiteSpace(model))
        {
            model = "ragflow";
        }

        try
        {
            var requestBody = new
            {
                input = text,
                model = model
            };

            var json = JsonSerializer.Serialize(requestBody);
            var content = new StringContent(json, Encoding.UTF8, "application/json");
            
            // 创建新的 HttpRequestMessage 以避免修改共享的 DefaultRequestHeaders
            var request = new HttpRequestMessage(HttpMethod.Post, 
                apiUrl.EndsWith("/embeddings", StringComparison.OrdinalIgnoreCase)
                    ? apiUrl
                    : $"{apiUrl.TrimEnd('/')}/embeddings");
            
            request.Content = content;
            
            // 确保 apiKey 不为 null，然后设置 Authorization
            if (!string.IsNullOrWhiteSpace(apiKey))
            {
                request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", apiKey);
            }
            
            var response = await _httpClient.SendAsync(request);
            
            var responseContent = await response.Content.ReadAsStringAsync();
            
            // 检查响应内容是否为空
            if (string.IsNullOrWhiteSpace(responseContent))
            {
                throw new InvalidOperationException("API返回的响应内容为空");
            }
            
            // 记录API响应内容用于调试（仅前500字符）
            if (!response.IsSuccessStatusCode)
            {
                Console.WriteLine($"API调用失败 [状态码: {response.StatusCode}]: {responseContent.Substring(0, Math.Min(500, responseContent.Length))}");
                throw new HttpRequestException($"API调用失败: {response.StatusCode} - {responseContent.Substring(0, Math.Min(200, responseContent.Length))}");
            }
            
            // 记录响应内容用于调试（仅前500字符）
            Console.WriteLine($"API响应内容预览: {responseContent.Substring(0, Math.Min(500, responseContent.Length))}");
            
            // 尝试多种响应格式
            float[] embedding = null;
            
            try
            {
                // 格式1: 标准OpenAI格式 {"data": [{"embedding": [...]}]}
                var embeddingResponse = JsonSerializer.Deserialize<EmbeddingResponse>(responseContent);
                embedding = embeddingResponse?.Data?.FirstOrDefault()?.Embedding;
                
                if (embedding != null && embedding.Length > 0)
                {
                    Console.WriteLine($"成功解析向量 [维度: {embedding.Length}]");
                    return embedding;
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine($"尝试标准格式解析失败: {ex.Message}");
            }
            
            // 格式2: RAGFlow格式 {"data": [{"embedding": [...]}]} 但可能字段名不同
            try
            {
                using var doc = JsonDocument.Parse(responseContent);
                var root = doc.RootElement;
                
                // 尝试查找 data 字段
                if (root.TryGetProperty("data", out var dataElement) && dataElement.ValueKind == JsonValueKind.Array)
                {
                    if (dataElement.GetArrayLength() > 0)
                    {
                        var firstItem = dataElement[0];
                        
                        // 尝试多种可能的字段名
                        if (firstItem.TryGetProperty("embedding", out var embeddingElement))
                        {
                            embedding = JsonSerializer.Deserialize<float[]>(embeddingElement.GetRawText());
                        }
                        else if (firstItem.TryGetProperty("vector", out var vectorElement))
                        {
                            embedding = JsonSerializer.Deserialize<float[]>(vectorElement.GetRawText());
                        }
                        else if (firstItem.TryGetProperty("embed", out var embedElement))
                        {
                            embedding = JsonSerializer.Deserialize<float[]>(embedElement.GetRawText());
                        }
                        
                        if (embedding != null && embedding.Length > 0)
                        {
                            Console.WriteLine($"成功解析向量 [维度: {embedding.Length}, 使用备用格式]");
                            return embedding;
                        }
                    }
                }
                
                // 如果data直接是数组
                if (root.ValueKind == JsonValueKind.Array)
                {
                    if (root.GetArrayLength() > 0)
                    {
                        var firstItem = root[0];
                        if (firstItem.TryGetProperty("embedding", out var embeddingElement))
                        {
                            embedding = JsonSerializer.Deserialize<float[]>(embeddingElement.GetRawText());
                            if (embedding != null && embedding.Length > 0)
                            {
                                Console.WriteLine($"成功解析向量 [维度: {embedding.Length}, 数组格式]");
                                return embedding;
                            }
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine($"尝试备用格式解析失败: {ex.Message}");
            }
            
            // 所有解析都失败
            Console.WriteLine($"无法解析API响应为向量。响应内容: {responseContent.Substring(0, Math.Min(1000, responseContent.Length))}");
            throw new InvalidOperationException($"API返回的向量为空或格式不正确。响应内容: {responseContent.Substring(0, Math.Min(200, responseContent.Length))}");
        }
        catch (Exception ex)
        {
            // 不再静默返回简单向量，而是抛出异常，让调用方知道失败
            Console.WriteLine($"生成嵌入向量失败 [文本长度: {text?.Length ?? 0}]: {ex.Message}");
            throw new InvalidOperationException($"生成嵌入向量失败: {ex.Message}", ex);
        }
    }

    /// <summary>
    /// 简化的向量生成（备用方案）
    /// </summary>
    private float[] GenerateSimpleVector(string text)
    {
        var hash = text.GetHashCode();
        // 使用配置的维度作为退避向量长度
        int dimension = 384;
        int.TryParse(_configuration["RAGSettings:VectorDimension"], out dimension);
        if (dimension <= 0) dimension = 384;
        var vector = new float[dimension];
        var random = new Random(hash);
        
        for (int i = 0; i < vector.Length; i++)
        {
            vector[i] = (float)(random.NextDouble() * 2 - 1);
        }
        
        return vector;
    }

    /// <summary>
    /// 生成向量并存储到Qdrant
    /// </summary>
    internal async Task GenerateAndStoreVectorAsync(long knowledgeId, string content, string title)
    {
        try
        {
            // 处理null值，确保不会因为null导致序列化失败
            title = title ?? string.Empty;
            content = content ?? string.Empty;
            
            // 合并标题和内容
            var combinedText = string.IsNullOrWhiteSpace(title) 
                ? content 
                : string.IsNullOrWhiteSpace(content) 
                    ? title 
                    : $"{title}\n{content}";
            
            // 如果合并后的文本为空，跳过向量生成并记录警告
            if (string.IsNullOrWhiteSpace(combinedText))
            {
                Console.WriteLine($"警告: 知识ID {knowledgeId} 的标题和内容都为空，跳过向量生成");
                return;
            }
            
            // 1. 生成向量
            var vector = await GenerateEmbeddingAsync(combinedText);
            
            // 2. 存储到Qdrant
            await StoreVectorInQdrantAsync(knowledgeId, vector, title, content);
            
            // 3. 本地也保存一份（备用）
            var knowledgeVector = new Admin.NET.Application.Entity.KnowledgeVector
            {
                KnowledgeId = knowledgeId,
                Vector = JsonSerializer.Serialize(vector),
                Dimension = vector.Length,
                Model = _configuration["RAGSettings:EmbeddingModel"] ?? "ragflow",
                CreateTime = DateTime.Now
            };
            
            await _vectorRepo.InsertAsync(knowledgeVector);
        }
        catch (Exception ex)
        {
            Console.WriteLine($"存储向量失败 [知识ID: {knowledgeId}, 标题: {title ?? "无标题"}]: {ex.Message}");
            throw; // 重新抛出异常，让调用方知道失败
        }
    }

    /// <summary>
    /// 存储向量到Qdrant
    /// </summary>
    private async Task StoreVectorInQdrantAsync(long knowledgeId, float[] vector, string title, string content)
    {
        try
        {
            var qdrantUrl = _configuration["RAGSettings:QdrantUrl"] ?? "http://localhost:6333";
            var collectionName = _configuration["RAGSettings:QdrantCollection"] ?? "wms_knowledge";
            
            var payload = new
            {
                knowledge_id = knowledgeId,
                title = title,
                content_text = content,
                created_at = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")
            };

            var requestBody = new
            {
                points = new[]
                {
                    new
                    {
                        id = knowledgeId,
                        vector = vector,
                        payload = payload
                    }
                }
            };

            var json = JsonSerializer.Serialize(requestBody);
            var httpContent = new StringContent(json, Encoding.UTF8, "application/json");
            
            var response = await _httpClient.PutAsync($"{qdrantUrl}/collections/{collectionName}/points", httpContent);
            response.EnsureSuccessStatusCode();
        }
        catch (Exception ex)
        {
            Console.WriteLine($"存储到Qdrant失败: {ex.Message}");
        }
    }

    /// <summary>
    /// 在Qdrant中搜索向量
    /// </summary>
    private async Task<List<VectorSearchResult>> SearchVectorsInQdrantAsync(float[] queryVector, int limit)
    {
        try
        {
            var qdrantUrl = _configuration["RAGSettings:QdrantUrl"] ?? "http://localhost:6333";
            var collectionName = _configuration["RAGSettings:QdrantCollection"] ?? "wms_knowledge";
            
            var requestBody = new
            {
                vector = queryVector,
                limit = limit,
                with_payload = true,
                score_threshold = 0.7f
            };

            var json = JsonSerializer.Serialize(requestBody);
            var content = new StringContent(json, Encoding.UTF8, "application/json");
            
            var response = await _httpClient.PostAsync($"{qdrantUrl}/collections/{collectionName}/points/search", content);
            response.EnsureSuccessStatusCode();
            
            var responseContent = await response.Content.ReadAsStringAsync();
            var searchResponse = JsonSerializer.Deserialize<QdrantSearchResponse>(responseContent);
            
            return searchResponse.Result.Select(r => new VectorSearchResult
            {
                KnowledgeId = r.Id,
                Score = r.Score
            }).ToList();
        }
        catch (Exception ex)
        {
            Console.WriteLine($"Qdrant搜索失败: {ex.Message}");
            return new List<VectorSearchResult>();
        }
    }

    /// <summary>
    /// 更新Qdrant中的向量
    /// </summary>
    internal async Task UpdateVectorInQdrantAsync(long knowledgeId, string content, string title)
    {
        try
        {
            // 1. 生成新向量
            var vector = await GenerateEmbeddingAsync($"{title}\n{content}");
            
            // 2. 更新Qdrant中的向量
            await StoreVectorInQdrantAsync(knowledgeId, vector, title, content);
            
            // 3. 更新本地向量
            var existingVector = await _vectorRepo.GetFirstAsync(v => v.KnowledgeId == knowledgeId);
            if (existingVector != null)
            {
                existingVector.Vector = JsonSerializer.Serialize(vector);
                existingVector.Dimension = vector.Length;
                await _vectorRepo.UpdateAsync(existingVector);
            }
        }
        catch (Exception ex)
        {
            Console.WriteLine($"更新Qdrant向量失败: {ex.Message}");
        }
    }

    /// <summary>
    /// 从Qdrant中删除向量
    /// </summary>
    private async Task DeleteVectorFromQdrantAsync(long knowledgeId)
    {
        try
        {
            var qdrantUrl = _configuration["RAGSettings:QdrantUrl"] ?? "http://localhost:6333";
            var collectionName = _configuration["RAGSettings:QdrantCollection"] ?? "wms_knowledge";
            
            var response = await _httpClient.PostAsync($"{qdrantUrl}/collections/{collectionName}/points/delete", 
                new StringContent(JsonSerializer.Serialize(new { points = new[] { knowledgeId } }), 
                Encoding.UTF8, "application/json"));
            
            response.EnsureSuccessStatusCode();
            
            // 同时物理删除本地向量
            await _vectorRepo.AsDeleteable().Where(v => v.KnowledgeId == knowledgeId).ExecuteCommandAsync();
        }
        catch (Exception ex)
        {
            Console.WriteLine($"从Qdrant删除向量失败: {ex.Message}");
        }
    }

    /// <summary>
    /// 初始化Qdrant集合
    /// </summary>
    [DisplayName("初始化向量数据库")]
    [ApiDescriptionSettings(Name = "InitializeQdrantCollection"), HttpPost]
    public async Task InitializeQdrantCollection()
    {
        try
        {
            var qdrantUrl = _configuration["RAGSettings:QdrantUrl"] ?? "http://localhost:6333";
            var collectionName = _configuration["RAGSettings:QdrantCollection"] ?? "wms_knowledge";
            
            // 创建集合
            var createCollectionRequest = new
            {
                vectors = new
                {
                    size = int.TryParse(_configuration["RAGSettings:VectorDimension"], out var dim) ? dim : 384,
                    distance = "Cosine"
                }
            };

            var json = JsonSerializer.Serialize(createCollectionRequest);
            var content = new StringContent(json, Encoding.UTF8, "application/json");
            
            var response = await _httpClient.PutAsync($"{qdrantUrl}/collections/{collectionName}", content);
            
            if (response.StatusCode == System.Net.HttpStatusCode.OK || 
                response.StatusCode == System.Net.HttpStatusCode.Created)
            {
                Console.WriteLine($"Qdrant集合 {collectionName} 初始化成功");
            }
            else
            {
                Console.WriteLine($"Qdrant集合初始化失败: {response.StatusCode}");
            }
        }
        catch (Exception ex)
        {
            Console.WriteLine($"初始化Qdrant集合失败: {ex.Message}");
        }
    }

    /// <summary>
    /// 批量导入知识
    /// </summary>
    [DisplayName("批量导入知识")]
    public async Task<ImportResult> ImportKnowledge(List<KnowledgeImportDto> knowledgeList)
    {
        var result = new ImportResult
        {
            Total = knowledgeList.Count,
            Success = 0,
            Failed = 0,
            Errors = new List<string>()
        };

        foreach (var item in knowledgeList)
        {
            try
            {
                var knowledge = new Admin.NET.Application.Entity.KnowledgeBase
                {
                    Title = item.Title,
                    Content = item.Content,
                    Category = item.Category,
                    Keywords = item.Keywords,
                    DocumentType = item.DocumentType ?? "text",
                    Source = item.Source ?? "import",
                    Priority = item.Priority ?? 1,
                    IsEnabled = true,
                    LastUpdated = DateTime.Now
                };

                var id = await _knowledgeRepo.InsertReturnSnowflakeIdAsync(knowledge);
                await GenerateAndStoreVectorAsync(id, knowledge.Content, knowledge.Title);
                
                result.Success++;
            }
            catch (Exception ex)
            {
                result.Failed++;
                result.Errors.Add($"导入失败: {item.Title} - {ex.Message}");
            }
        }

        return result;
    }

    /// <summary>
    /// 计算相关性分数
    /// </summary>
    private float CalculateRelevanceScore(Admin.NET.Application.Entity.KnowledgeBase knowledge, string query)
    {
        float score = 0;
        
        if (knowledge.Title.Contains(query)) score += 0.4f;
        if (knowledge.Content.Contains(query)) score += 0.3f;
        if (knowledge.Keywords.Contains(query)) score += 0.2f;
        if (knowledge.SimilarityScore.HasValue) score += knowledge.SimilarityScore.Value * 0.1f;
        
        return score;
    }

    /// <summary>
    /// 获取知识分类
    /// </summary>
    [DisplayName("获取知识分类")]
    [ApiDescriptionSettings(Name = "GetCategories"), HttpGet]
    public async Task<List<Admin.NET.Application.Entity.KnowledgeCategory>> GetCategories()
    {
        return await _categoryRepo.GetListAsync(c => c.IsEnabled);
    }

    /// <summary>
    /// 添加知识分类
    /// </summary>
    [DisplayName("添加知识分类")]
    public async Task<long> AddCategory(Admin.NET.Application.Entity.KnowledgeCategory input)
    {
        return await _categoryRepo.InsertReturnSnowflakeIdAsync(input);
    }

    /// <summary>
    /// 更新知识分类
    /// </summary>
    [DisplayName("更新知识分类")]
    public async Task UpdateCategory(Admin.NET.Application.Entity.KnowledgeCategory input)
    {
        await _categoryRepo.UpdateAsync(input);
    }

    /// <summary>
    /// 删除知识分类
    /// </summary>
    [ApiDescriptionSettings(Name = "DeleteCategory"), HttpPost]
    [DisplayName("删除知识分类")]
    public async Task DeleteCategory([FromBody] BaseIdInput? input, [FromForm] long? fid, [FromQuery] long? qid)
    {
        var realId = (input?.Id) ?? fid ?? qid ?? 0;
        if (realId <= 0) throw new ArgumentException("无效的Id");
        // 物理删除分类
        await _categoryRepo.AsDeleteable().Where(c => c.Id == realId).ExecuteCommandAsync();
    }

    /// <summary>
    /// 同步现有知识库到向量数据库（支持按ID选择与仅缺失向量）
    /// </summary>
    [DisplayName("同步现有知识库到向量数据库")]
    [ApiDescriptionSettings(Name = "SyncExistingKnowledgeToVector"), HttpPost]
    public async Task<KnowledgeSyncResult> SyncExistingKnowledgeToVector([FromBody] SyncVectorInput? input)
    {
        var result = new KnowledgeSyncResult
        {
            Total = 0,
            Success = 0,
            Failed = 0,
            Errors = new List<string>()
        };

        try
        {
            // 基础查询：启用且未删除
            var query = _knowledgeRepo.AsQueryable().Where(k => k.IsEnabled && !k.IsDelete);

            // 仅同步选中的ID
            if (input != null && input.Ids != null && input.Ids.Count > 0)
            {
                var ids = input.Ids.Distinct().ToList();
                query = query.In(k => k.Id, ids);
            }

            var allKnowledge = await query.ToListAsync();
            result.Total = allKnowledge.Count;

            Console.WriteLine($"找到 {result.Total} 条知识库记录，开始同步到向量数据库...");

            foreach (var knowledge in allKnowledge)
            {
                try
                {
                    // 检查是否已有向量
                    var existingVector = await _vectorRepo.GetFirstAsync(v => v.KnowledgeId == knowledge.Id && !v.IsDelete);

                    if (input?.MissingOnly == true)
                    {
                        // 仅处理缺失向量：本地无向量或Qdrant不存在
                        var existsInQdrant = await CheckVectorExistsInQdrantAsync(knowledge.Id);
                        var missing = existingVector == null || !existsInQdrant;
                        if (!missing)
                        {
                            // 缺省情况下跳过
                            Console.WriteLine($"已存在向量（本地与Qdrant均存在），跳过: {knowledge.Title}");
                            continue;
                        }
                        // 对缺失的场景直接生成
                        await GenerateAndStoreVectorAsync(knowledge.Id, knowledge.Content, knowledge.Title);
                        Console.WriteLine($"生成/修复缺失向量成功: {knowledge.Title}");
                        result.Success++;
                        continue;
                    }

                    if (existingVector != null)
                    {
                        // 如果已有向量，检查是否需要更新（如果内容已更改）
                        var existingVectorInQdrant = await CheckVectorExistsInQdrantAsync(knowledge.Id);
                        
                        if (!existingVectorInQdrant)
                        {
                            // 向量不存在于Qdrant，重新存储
                            await GenerateAndStoreVectorAsync(knowledge.Id, knowledge.Content, knowledge.Title);
                            Console.WriteLine($"重新生成向量成功: {knowledge.Title}");
                            result.Success++;
                        }
                        else
                        {
                            // 已存在，跳过
                            Console.WriteLine($"已存在向量，跳过: {knowledge.Title}");
                            result.Success++;
                        }
                    }
                    else
                    {
                        // 没有向量，生成并存储
                        await GenerateAndStoreVectorAsync(knowledge.Id, knowledge.Content, knowledge.Title);
                        Console.WriteLine($"生成向量成功: {knowledge.Title}");
                        result.Success++;
                    }
                }
                catch (Exception ex)
                {
                    result.Failed++;
                    result.Errors.Add($"同步失败 [{knowledge.Id}] {knowledge.Title}: {ex.Message}");
                    Console.WriteLine($"同步失败: {knowledge.Title} - {ex.Message}");
                }
            }
        }
        catch (Exception ex)
        {
            result.Errors.Add($"同步过程失败: {ex.Message}");
            Console.WriteLine($"同步过程失败: {ex.Message}");
        }

        return result;
    }

    /// <summary>
    /// 检查Qdrant中是否存在向量
    /// </summary>
    internal async Task<bool> CheckVectorExistsInQdrantAsync(long knowledgeId)
    {
        try
        {
            var qdrantUrl = _configuration["RAGSettings:QdrantUrl"] ?? "http://localhost:6333";
            var collectionName = _configuration["RAGSettings:QdrantCollection"] ?? "wms_knowledge";

            var response = await _httpClient.GetAsync($"{qdrantUrl}/collections/{collectionName}/points/{knowledgeId}");
            return response.IsSuccessStatusCode;
        }
        catch
        {
            return false;
        }
    }
}

// 知识库同步结果模型（避免与RAGFlowSyncService中的SyncResult冲突）
public class KnowledgeSyncResult
{
    public int Total { get; set; }
    public int Success { get; set; }
    public int Failed { get; set; }
    public List<string> Errors { get; set; } = new();
}

// 向量搜索结果
public class VectorSearchResult
{
    public long KnowledgeId { get; set; }
    public float Score { get; set; }
}

// OpenAI Embedding响应模型
public class EmbeddingResponse
{
    public EmbeddingData[] Data { get; set; }
}

public class EmbeddingData
{
    public float[] Embedding { get; set; }
}

// Qdrant搜索响应模型
public class QdrantSearchResponse
{
    public QdrantSearchResult[] Result { get; set; }
}

public class QdrantSearchResult
{
    public long Id { get; set; }
    public float Score { get; set; }
    public object Payload { get; set; }
}

// 选择性同步输入
public class SyncVectorInput
{
    public List<long>? Ids { get; set; }
    public bool? MissingOnly { get; set; }
}

// 导入结果模型
public class ImportResult
{
    public int Total { get; set; }
    public int Success { get; set; }
    public int Failed { get; set; }
    public List<string> Errors { get; set; } = new();
}

// 知识导入DTO
public class KnowledgeImportDto
{
    public string Title { get; set; }
    public string Content { get; set; }
    public string Category { get; set; }
    public string? Keywords { get; set; }
    public string? DocumentType { get; set; }
    public string? Source { get; set; }
    public int? Priority { get; set; }
}

// 分页输入模型
public class PageInput
{
    public int Page { get; set; } = 1;
    public int PageSize { get; set; } = 20;
    public string? Keyword { get; set; }
    public string? Category { get; set; }
}